package com.uy.system.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.uy.system.common.constant.SystemConstants;
import com.uy.system.common.utils.SessionUtils;
import com.uy.system.distribute.DistributedCacheService;
import com.uy.system.exception.ErrorCode;
import com.uy.system.exception.SystemException;
import com.uy.system.model.dto.CaptchaResult;
import com.uy.system.model.dto.LoginDTO;
import com.uy.system.model.entity.SysUser;
import com.uy.system.model.enums.CaptchaTypeEnum;
import com.uy.system.model.enums.HttpCode;
import com.uy.system.model.vo.LoginVo;
import com.uy.system.model.vo.SysUserVo;
import com.uy.system.plugin.captcha.CaptchaProperties;
import com.uy.system.service.IAuthService;
import com.uy.system.service.ISysUserService;
import com.uy.system.utils.BeanUtils;
import com.uy.system.utils.EncryptionUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.awt.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author LY
 * @create 2024/3/25 11:55
 * @Description 认证服务
 */
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements IAuthService {

    private final DistributedCacheService distributedCacheService;
    private final ISysUserService iSysUserService;
    private final CodeGenerator codeGenerator;
    private final Font captchaFont;
    private final CaptchaProperties captchaProperties;

    @Override
    public LoginVo doLogin(LoginDTO dto) {
        // 校验图文验证码
        String key = buildCapthaKey(dto.getCaptchaKey());
        // 缓存中的验证码
        String cacheVerifyCode = distributedCacheService.get(key);
        if (StrUtil.isBlank(cacheVerifyCode)){
            throw new SystemException(ErrorCode.CAPTCHA_VERIFY_EXPIRE);
        }
        // 验证码比对
        if (!codeGenerator.verify(cacheVerifyCode, dto.getCaptchaCode())){
            throw new SystemException(ErrorCode.CAPTCHA_VERIFY_ERROR);
        }

        SysUser sysUser = iSysUserService.findSysUser(dto.getUsername(), EncryptionUtil.encryptAES(dto.getPassword()));
        SysUserVo vo = BeanUtils.copyProperties(sysUser, SysUserVo.class);
        // 登录
        StpUtil.login(sysUser.getUserId());
        // 获取token
        String accessToken = StpUtil.getTokenValue();
        // 缓存登录用户信息
        SessionUtils.cacheSysUser(sysUser);
        return LoginVo.builder()
                .tokenType("Bearer")
                .accessToken(accessToken)
                .userVo(vo)
                .build();
    }

    @Override
    public String logout() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(SystemConstants.ACCESS_TOKEN);
        if (StrUtil.isBlank(token)) {
            return HttpCode.INVALID_TOKEN.getMsg();
        }
        StpUtil.logout();
        return null;
    }

    @Override
    public CaptchaResult getCaptcha() {
        String captchaType = captchaProperties.getType();
        int width = captchaProperties.getWidth();
        int height = captchaProperties.getHeight();
        int interfereCount = captchaProperties.getInterfereCount();
        int codeLength = captchaProperties.getCode().getLength();

        AbstractCaptcha captcha;
        if (CaptchaTypeEnum.CIRCLE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createCircleCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.GIF.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createGifCaptcha(width, height, codeLength);
        } else if (CaptchaTypeEnum.LINE.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createLineCaptcha(width, height, codeLength, interfereCount);
        } else if (CaptchaTypeEnum.SHEAR.name().equalsIgnoreCase(captchaType)) {
            captcha = CaptchaUtil.createShearCaptcha(width, height, codeLength, interfereCount);
        } else {
            throw new IllegalArgumentException("Invalid captcha type: " + captchaType);
        }
        captcha.setGenerator(codeGenerator);
        captcha.setTextAlpha(captchaProperties.getTextAlpha());
        captcha.setFont(captchaFont);
        // 验证图文内容
        String captchaCode = captcha.getCode();
        // 验证图文base64
        String imageBase64Data = captcha.getImageBase64Data();

        // 验证码文本缓存至Redis，用于登录校验
        String captchaKey = IdUtil.fastSimpleUUID();
        String key = buildCapthaKey(captchaKey);
        distributedCacheService.set(key, captchaCode, captchaProperties.getExpireSeconds(), TimeUnit.SECONDS);
        return CaptchaResult.builder()
                .captchaKey(captchaKey)
                .captchaBase64(imageBase64Data)
                .build();
    }

    /**
     * 拼接缓存图文key
     */
    public String buildCapthaKey(String captchaKey){
        return SystemConstants.CAPTCHA_CODE_PREFIX + captchaKey;
    }
}
